package com.ys.erp.stage_emp_service.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ys.erp.common.enums.EnableEnum;
import com.ys.erp.common.enums.RedisKey;
import com.ys.erp.common.util.EncryptionUtil;
import com.ys.erp.entity.data.bean.*;
import com.ys.erp.entity.service.*;
import com.ys.erp.entity.service.impl.IEmployeeServiceImpl;
import com.ys.erp.framework.bean.dto.EmpDTO;
import com.ys.erp.framework.bean.dto.StageEmpDTO;
import com.ys.erp.framework.exception.YsException;
import com.ys.erp.framework.response.AbstractResponseCode;
import com.ys.erp.framework.response.PageDTO;
import com.ys.erp.stage_emp_service.bean.conditon.EmpCondition;
import com.ys.erp.stage_emp_service.bean.vo.EmpLoginVO;
import com.ys.erp.stage_emp_service.bean.vo.EmpShopInfoVO;
import com.ys.erp.stage_emp_service.bean.vo.EmployeeVo;
import com.ys.erp.stage_emp_service.bean.vo.ShopInfoVO;
import com.ys.erp.stage_emp_service.service.EmpService;
import com.ys.erp.stage_emp_service.utils.DingDingUtil;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 南山
 * @date 2025/07/25 16:12
 */
@Service
@RequiredArgsConstructor
public class EmpServiceImpl implements EmpService {

    private final IEmployeeServiceImpl iEmployeeService;

    private final IShopService iShopService;

    private final IEmpShopService iEmpShopService;

    private final IRoleService iRoleService;


    private final IRightService iRightService;

    private final DingDingUtil dingDingUtil;
    private final IEventLogService iEventLogService;


    @Value("${properties.emp-password-salt}")
    private String empPasswordSalt;

    private final RedisTemplate<String, String> redisTemplate;

    @Override
    public EmpLoginVO empLogin(EmpCondition.EmpLoginCondition con) {
        String password = EncryptionUtil.md5Encryption(con.getPassword(), empPasswordSalt);
        QueryWrapper<Employee> qw = new QueryWrapper<>();
        qw.lambda().eq(Employee::getPhone, con.getAccount());
        //查询
        Employee emp = iEmployeeService.getOne(qw);
        if (ObjectUtil.isEmpty(emp)) {
            throw new YsException(AbstractResponseCode.LOGIN_ERROR);
        }
        if (!emp.getPassword().equals(password)) {
            //查询redis是否有失败记录
            String errorCount = redisTemplate.opsForValue().get(RedisKey.Enums.EMP_LOGIN_ERROR.getKey() + "_" + con.getAccount());
            if (StringUtils.isNotBlank(errorCount) && Integer.parseInt(errorCount) >= 2) {
                emp.setIsDisable(EnableEnum.YES.getEnable());
                iEmployeeService.updateById(emp);
                throw new YsException(AbstractResponseCode.EMP_ACC_DISABLE);
            }
            if (StringUtils.isBlank(errorCount)) {
                redisTemplate.opsForValue().set(RedisKey.Enums.EMP_LOGIN_ERROR.getKey() + con.getAccount(), "0", 60, TimeUnit.MINUTES);
                throw new YsException(AbstractResponseCode.LOGIN_ERROR);
            }
            redisTemplate.opsForValue().set(RedisKey.Enums.EMP_LOGIN_ERROR.getKey() + "_" + con.getAccount(), String.valueOf((Integer.parseInt(errorCount) + 1)), 60, TimeUnit.MINUTES);
            throw new YsException(AbstractResponseCode.LOGIN_ERROR);
        }
        if (emp.getIsDisable() == EnableEnum.YES.getEnable()) {
            throw new YsException(AbstractResponseCode.EMP_ACC_DISABLE);
        }
        //根据员工查询角色
        Role role = iRoleService.getById(emp.getRoleId());
        JSONArray idArr = JSONArray.parseArray(role.getRightIds());
        //查询权限
        List<Right> rights = iRightService.listByIds(idArr.toJavaList(Long.class));
        EmpDTO empDto = new EmpDTO();
        empDto.setId(emp.getId());
        empDto.setPhone(emp.getPhone());
        empDto.setRealName(emp.getRealName());
        empDto.setRoleName(role.getRoleName());
        empDto.setPassword(emp.getPassword());
        empDto.setParentId(emp.getParentId());
        empDto.setBankAccount(emp.getBankAccount());
        empDto.setBankName(emp.getBankName());
        empDto.setRoleId(emp.getRoleId());
        empDto.setDingdingUserId(emp.getDingdingUserId());
        empDto.setRightFlags(rights.stream().map(Right::getRightKey).collect(Collectors.toList()));
        EmpLoginVO adminDetailVO = new EmpLoginVO();
        //生成token
        String token = EncryptionUtil.generateUuid();
        redisTemplate.opsForValue().set(RedisKey.Enums.EMP_LOGIN_FLAG.getKey() + token, JSONObject.toJSONString(empDto), 60 * 24, TimeUnit.MINUTES);
        return adminDetailVO.setToken(token);
    }


    @Override
    public List<ShopInfoVO> getEmpShopInfoList(StageEmpDTO empDto) {
        List<String> shopCodeList = iEmpShopService.getShopCodeListByShopId(empDto.getId());
        return getShopInfoVoList(shopCodeList);
    }

    @Override
    public EmpShopInfoVO chooseShop(StageEmpDTO empDto, String shopCode) {
        List<String> shopCodeList = iEmpShopService.getShopCodeListByShopId(empDto.getId());
        if (CollectionUtils.isEmpty(shopCodeList)) {
            throw new YsException(-1, "该账号下没有店铺，无法进入");
        }
        if (!shopCodeList.contains(shopCode)) {
            throw new YsException(-1, "该账号下不存在此店铺，无法进入");
        }

        Shop shop = iShopService.getByCode(shopCode);
        if (Objects.isNull(shop)) {
            throw new YsException(-1, "店铺不存在");
        }
        empDto.setShopCode(shop.getShopCode());
        empDto.setShopName(shop.getName());
        empDto.setShopGrade(shop.getShopGrade());
        empDto.setIsJoinBus(shop.getIsJoinBus());
        redisTemplate.opsForValue().set(RedisKey.Enums.EMP_LOGIN_FLAG.getKey() + empDto.getToken(),
                JSONObject.toJSONString(empDto), 60 * 24, TimeUnit.MINUTES);
        EmpShopInfoVO empShopInfoVO = new EmpShopInfoVO();
        BeanUtils.copyProperties(empDto, empShopInfoVO);
        return empShopInfoVO;
    }


    @Override
    public List<ShopInfoVO> getEmpShopList(StageEmpDTO empDto, Long empId) {
        List<String> shopCodeList = iEmpShopService.getShopCodeListByShopId(empId);
        return getShopInfoVoList(shopCodeList);
    }

    @NotNull
    private List<ShopInfoVO> getShopInfoVoList(List<String> shopCodeList) {
        List<Shop> shopList = iShopService.getShopListByCodeList(shopCodeList);
        ArrayList<ShopInfoVO> shopInfoVoList = new ArrayList<>();
        for (Shop shop : shopList) {
            ShopInfoVO shopInfoVO = new ShopInfoVO();
            shopInfoVO.setShopCode(shop.getShopCode());
            shopInfoVO.setShopName(shop.getName());
            shopInfoVoList.add(shopInfoVO);
        }
        return shopInfoVoList;
    }

    @Override
    public void empSettingShop(StageEmpDTO empDto, EmpCondition.EmpSettingShopCon con) {
        if (CollectionUtils.isEmpty(con.getShopCodeList())) {
            throw new YsException(-1, "请选择店铺");
        }
        QueryWrapper<EmpShop> empShopQw = new QueryWrapper<>();
        empShopQw.lambda().eq(EmpShop::getEmpId, con.getEmpId());
        iEmpShopService.remove(empShopQw);
        ArrayList<EmpShop> empShopList = new ArrayList<>();
        for (String shopCode : con.getShopCodeList()) {
            EmpShop empShop = new EmpShop();
            empShop.setEmpId(con.getEmpId());
            empShop.setShopCode(shopCode);
            empShopList.add(empShop);
        }
        iEmpShopService.saveBatch(empShopList);

    }

    @Override
    public PageDTO<EmployeeVo> pageEmp(StageEmpDTO empDto, EmpCondition.PageEmployeeCon pageEmployeeCon) {
        QueryWrapper<Employee> empQw = new QueryWrapper<>();
        if (!"hz0".equals(empDto.getShopCode())) {
            setEmpQwShopCode(empQw, empDto.getShopCode());
        }
        if (ObjectUtil.isNotEmpty(pageEmployeeCon.getShopCode())) {
            setEmpQwShopCode(empQw, pageEmployeeCon.getShopCode());
        }
        if (ObjectUtil.isNotEmpty(pageEmployeeCon.getRealName())) {
            empQw.lambda().like(Employee::getRealName, pageEmployeeCon.getRealName());
        }
        if (ObjectUtil.isNotEmpty(pageEmployeeCon.getPhone())) {
            empQw.lambda().like(Employee::getPhone, pageEmployeeCon.getPhone());
        }

        if (ObjectUtil.isNotEmpty(pageEmployeeCon.getRoleId())) {
            empQw.lambda().eq(Employee::getRoleId, pageEmployeeCon.getRoleId());
        }
        if (ObjectUtil.isNotEmpty(pageEmployeeCon.getStatusDescribe())) {
            empQw.lambda().like(Employee::getStatusDescribe, pageEmployeeCon.getStatusDescribe());
        }
        if (ObjectUtil.isNotEmpty(pageEmployeeCon.getIsDepart()) && pageEmployeeCon.getIsDepart() == EnableEnum.YES.getEnable()) {
            empQw.lambda().like(Employee::getStatusDescribe, "离职");
        }

        Page<Employee> employeePage = new Page<>(pageEmployeeCon.getCurrent(), pageEmployeeCon.getSize());
        Page<Employee> page = iEmployeeService.page(employeePage, empQw);
        if (page.getRecords().isEmpty()) {
            return new PageDTO<>(page.getCurrent(), 0L, new ArrayList<>());
        }
        List<Employee> records = page.getRecords();
        List<Long> roleIdList = records.stream().map(Employee::getRoleId).toList();
        List<Long> empIdList = records.stream().map(Employee::getId).toList();
        QueryWrapper<Role> roleQw = new QueryWrapper<>();
        roleQw.lambda().in(Role::getId, roleIdList);
        List<Role> roleList = iRoleService.list(roleQw);
        Map<Long, Role> roleMap = roleList.stream().collect(Collectors.toMap(Role::getId, Function.identity()));
        QueryWrapper<EmpShop> empShopQw = new QueryWrapper<>();
        empShopQw.lambda().in(EmpShop::getEmpId, empIdList);
        List<EmpShop> empShopList = iEmpShopService.list(empShopQw);
        List<String> shopCodeList = empShopList.stream().map(EmpShop::getShopCode).distinct().toList();
        List<Shop> shopListByCodeList = iShopService.getShopListByCodeList(shopCodeList);
        Map<String, Shop> shopMap = shopListByCodeList.stream().collect(Collectors.toMap(Shop::getShopCode, Function.identity()));
        Map<Long, List<EmpShop>> empShopListMap = empShopList.stream().collect(Collectors.groupingBy(EmpShop::getEmpId));
        List<EmployeeVo> employeeVOList = page.getRecords().stream().map(it -> {
            EmployeeVo employeeVo = new EmployeeVo();
            BeanUtils.copyProperties(it, employeeVo);
            Role role = roleMap.get(it.getRoleId());
            employeeVo.setRoleName(Objects.isNull(role) ? "" : role.getRoleName());
            List<EmpShop> empShops = empShopListMap.get(it.getId());
            if (CollectionUtils.isEmpty(empShops)) {
                employeeVo.setShopCode("");
                employeeVo.setShopName("");
            } else {
                StringBuilder shopList = new StringBuilder();
                for (EmpShop empShop : empShops) {
                    Shop shop = shopMap.get(empShop.getShopCode());
                    shopList.append(Objects.isNull(shop) ? "" : shop.getName());
                }
                employeeVo.setShopName(shopList.toString());
            }

            return employeeVo;
        }).collect(Collectors.toList());
        return new PageDTO<>(employeePage.getCurrent(), page.getTotal(), employeeVOList);
    }


    @Override
    public void addOrUpdateEmployee(StageEmpDTO empDto, EmpCondition.@Valid AddOrUpdateEmpCon con) {
        Employee employee = new Employee();
        if (ObjectUtil.isEmpty(con.getParentId())) {
            con.setParentId(0L);
        }
        Role role = iRoleService.getById(con.getRoleId());
        if (ObjectUtil.isEmpty(role)) {
            throw new YsException(-1, "该角色不属于该门店下的数据");
        }
        Shop loginShop = iShopService.getByCode(empDto.getShopCode());
        List<Shop> conShop = iShopService.getShopListByCodeList(con.getShopCodeList());
        if (CollectionUtils.isEmpty(conShop) || ObjectUtil.isEmpty(loginShop)) {
            throw new YsException(AbstractResponseCode.VALID_ERROR);
        }
        String childShop = loginShop.getChildShop();
        if (ObjectUtil.isEmpty(childShop)) {
            childShop = "[]";
        }
        List<Long> shopIds = JSONArray.parseArray(childShop, Long.class);
        shopIds.add(loginShop.getId());
        List<Shop> shopList = conShop.stream().filter(it -> shopIds.contains(it.getId())).toList();
        if (CollectionUtils.isEmpty(shopList)) {
            throw new YsException(AbstractResponseCode.VALID_ERROR);
        }
        Shop first = shopList.getFirst();
        employee.setShopId(first.getId())
                .setShopCode(first.getShopCode())
                .setRoleId(con.getRoleId())
                .setRealName(con.getRealName())
                .setPhone(con.getPhone())
                .setPassword(EncryptionUtil.md5Encryption("123456", empPasswordSalt))
                .setIsDisable(con.getIsDisable())
                .setStatusDescribe(con.getStatusDescribe())
                .setParentId(con.getParentId())
                .setBankAccount(con.getBankAccount())
                .setBankName(con.getBankName());
        if (ObjectUtil.isEmpty(con.getId())) {
            String dingDingUserId = dingDingUtil.getUserIdByPhone(con.getPhone());
            Employee phoneEmp = iEmployeeService.getEmpByPhone(con.getPhone());
            if (ObjectUtil.isNotEmpty(phoneEmp)) {
                throw new YsException(-1, "此手机号禁止添加");
            }
            employee.setDingdingUserId(dingDingUserId);
            //新增
            iEmployeeService.save(employee);
            addEmpShop(employee, shopList);
            //增加日志
            iEventLogService.insertEvent(empDto, "新增员工：" + employee.getId(), employee.getId(), EnableEnum.NO.getEnable(), JSONObject.toJSONString(con));
            return;
        }
        QueryWrapper<EmpShop> empShopQw = new QueryWrapper<>();
        empShopQw.lambda().eq(EmpShop::getEmpId, con.getId());
        iEmpShopService.remove(empShopQw);
        //编辑，查询
        Employee dbEmp = iEmployeeService.getById(con.getId());
        if (ObjectUtil.isEmpty(dbEmp)) {
            throw new YsException(AbstractResponseCode.VALID_ERROR);
        }
        //编辑
        employee.setId(dbEmp.getId())
                .setPhone(dbEmp.getPhone())
                .setPassword(dbEmp.getPassword())
                .setVersion(dbEmp.getVersion());
        iEmployeeService.updateById(employee);
        addEmpShop(employee, shopList);
        //增加日志
        iEventLogService.insertEvent(empDto, "编辑员工：" + employee.getId() + " 编辑前信息" + JSONObject.toJSONString(dbEmp), employee.getId(), EnableEnum.NO.getEnable(), JSONObject.toJSONString(con));

    }

    private void addEmpShop(Employee employee, List<Shop> shopList) {
        List<EmpShop> empShopList = new ArrayList<>();
        for (Shop shop : shopList) {
            EmpShop empShop = new EmpShop();
            empShop.setEmpId(employee.getId());
            empShop.setShopCode(shop.getShopCode());
            empShopList.add(empShop);
        }
        iEmpShopService.saveBatch(empShopList);
    }

    private void setEmpQwShopCode(QueryWrapper<Employee> empQw, String shopCode) {
        QueryWrapper<EmpShop> empShopQw = new QueryWrapper<>();
        empShopQw.lambda().eq(EmpShop::getShopCode, shopCode);
        List<EmpShop> empShopList = iEmpShopService.list(empShopQw);
        if (CollectionUtils.isEmpty(empShopList)) {
            empQw.lambda().in(Employee::getId, "-1");
        } else {
            empQw.lambda().in(Employee::getId, empShopList);
        }
    }

}
